package com.coderising.jvm.engine;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import com.coderising.jvm.cmd.ByteCodeCommand;
import com.coderising.jvm.method.Method;

public class StackFrame {

	private List<JavaObject> localVariableTable = new ArrayList<JavaObject>();
	private Stack<JavaObject> oprandStack = new Stack<JavaObject>();

	int index = 0;

	private Method m = null;

	private StackFrame callerFrame = null;

	public StackFrame getCallerFrame() {
		return callerFrame;
	}

	public void setCallerFrame(StackFrame callerFrame) {
		this.callerFrame = callerFrame;
	}

	public static StackFrame create(Method m) {

		StackFrame frame = new StackFrame(m);

		return frame;
	}

	private StackFrame(Method m) {
		this.m = m;

	}

	public JavaObject getLocalVariableValue(int index) {
		return this.localVariableTable.get(index);
	}

	public Stack<JavaObject> getOprandStack() {
		return this.oprandStack;
	}

	public int getNextCommandIndex(int offset) {

		ByteCodeCommand[] cmds = m.getCodeAttr().getCmds();
		for (int i = 0; i < cmds.length; i++) {
			if (cmds[i].getOffset() == offset) {
				return i;
			}
		}
		throw new RuntimeException("Can't find next command");
	}

	public ExecutionResult execute() {

		ByteCodeCommand[] cmds = m.getCmds();

		while (index < cmds.length) {

			ExecutionResult result = new ExecutionResult();
			// 缺省值是执行下一条命令
			result.setNextAction(ExecutionResult.RUN_NEXT_CMD);

			System.out.println(cmds[index].toString());

			cmds[index].execute(this, result);

			if (result.isRunNextCmd()) {
				index++;
			} else if (result.isExitCurrentFrame()) {
				return result;
			} else if (result.isPauseAndRunNewFrame()) {
				index++;
				return result;
			} else if (result.isJump()) {
				int offset = result.getNextCmdOffset();
				this.index = getNextCommandIndex(offset);
			} else {
				index++;
			}

		}

		// 当前StackFrmae的指令全部执行完毕，可以退出了
		ExecutionResult result = new ExecutionResult();
		result.setNextAction(ExecutionResult.EXIT_CURRENT_FRAME);
		return result;

	}

	public void setLocalVariableTable(List<JavaObject> values) {
		this.localVariableTable = values;
	}

	public void setLocalVariableValue(int index, JavaObject jo) {
		// 问题： 为什么要这么做？？
		if (this.localVariableTable.size() - 1 < index) {
			for (int i = this.localVariableTable.size(); i <= index; i++) {
				this.localVariableTable.add(null);
			}
		}
		this.localVariableTable.set(index, jo);

	}

	public Method getMethod() {
		return m;
	}

}